﻿// -----------------------------------------------------------------------
// <copyright file="ArithmaticLogicOperations.cs" company="Image Processing Course Project">
// Created 25/10/2011
// </copyright>
// -----------------------------------------------------------------------

namespace ImageProcessing.IntermediateClasses
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using ImageProcessing.Utilities;

    /// <summary>
    /// Class for Arithmatic and Logical related image operations
    /// </summary>
    public class ArithmaticLogicOperations
    {
        /// <summary>
        /// Local object from ImageGeometry class
        /// </summary>
        private ImageGeometry geometry = new ImageGeometry();

        /// <summary>
        /// Adds two images into one accourding to a specified fraction
        /// </summary>
        /// <param name="img1">First image</param>
        /// <param name="img2">Second image</param>
        /// <param name="fraction">Fraction specifying the percentage of color to take from each image</param>
        /// <returns>Addition resulting Bitmap image</returns>
        public Bitmap Add(Image img1, Image img2, double fraction)
        {
            Bitmap imgResult = new Bitmap(img1.Width, img1.Height);
            int red, green, blue;

            try
            {
                Bitmap img2BMP = new Bitmap(this.geometry.BilinearResize(img2, img1.Width, img1.Height));
                Bitmap img1BMP = new Bitmap(img1);

                for (int i = 0; i < img1.Width; i++)
                {
                    for (int j = 0; j < img1.Height; j++)
                    {
                        red = (int)((img1BMP.GetPixel(i, j).R * fraction) + (img2BMP.GetPixel(i, j).R * (1 - fraction)));
                        green = (int)((img1BMP.GetPixel(i, j).G * fraction) + (img2BMP.GetPixel(i, j).G * (1 - fraction)));
                        blue = (int)((img1BMP.GetPixel(i, j).B * fraction) + (img2BMP.GetPixel(i, j).B * (1 - fraction)));
                        imgResult.SetPixel(i, j, Color.FromArgb(red, green, blue));
                    }
                }

                return imgResult;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Subtracts the second image from the first image
        /// </summary>
        /// <param name="img1">First image</param>
        /// <param name="img2">Second image</param>
        /// <returns>Subtraction resulting Bitmap image</returns>
        public Bitmap Subtract(Image img1, Image img2)
        {
            Bitmap imgResult = new Bitmap(img1.Width, img1.Height);
            int red, green, blue;

            try
            {
                Bitmap img1BMP = new Bitmap(img1);
                Bitmap img2BMP = new Bitmap(this.geometry.BilinearResize(img2, img1.Width, img1.Height));

                for (int i = 0; i < img1.Width; i++)
                {
                    for (int j = 0; j < img1.Height; j++)
                    {
                        red = img1BMP.GetPixel(i, j).R - img2BMP.GetPixel(i, j).R;
                        green = img1BMP.GetPixel(i, j).G - img2BMP.GetPixel(i, j).G;
                        blue = img1BMP.GetPixel(i, j).B - img2BMP.GetPixel(i, j).B;

                        if (red < 0)
                        {
                            red = 0;
                        }
                        else if (red > 255)
                        {
                            red = 255;
                        }

                        if (green < 0)
                        {
                            green = 0;
                        }
                        else if (green > 255)
                        {
                            green = 255;
                        }

                        if (blue < 0)
                        {
                            blue = 0;
                        }
                        else if (blue > 255)
                        {
                            blue = 255;
                        }

                        imgResult.SetPixel(i, j, Color.FromArgb(red, green, blue));
                    }
                }

                return imgResult;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// AND logical operation on two images
        /// </summary>
        /// <param name="img1">First image</param>
        /// <param name="img2">Second image</param>
        /// <returns>AND resulting Bitmap image</returns>
        public Bitmap And(Image img1, Image img2)
        {
            Bitmap imgResult = new Bitmap(img1.Width, img1.Height);
            int red, green, blue;

            try
            {
                Bitmap img1BMP = new Bitmap(img1);
                Bitmap img2BMP = new Bitmap(this.geometry.BilinearResize(img2, img1.Width, img1.Height));

                for (int i = 0; i < img1.Width; i++)
                {
                    for (int j = 0; j < img1.Height; j++)
                    {
                        red = img1BMP.GetPixel(i, j).R & img2BMP.GetPixel(i, j).R;
                        green = img1BMP.GetPixel(i, j).G & img2BMP.GetPixel(i, j).G;
                        blue = img1BMP.GetPixel(i, j).B & img2BMP.GetPixel(i, j).B;
                        imgResult.SetPixel(i, j, Color.FromArgb(red, green, blue));
                    }
                }

                return imgResult;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// OR logical operation on two images
        /// </summary>
        /// <param name="img1">First image</param>
        /// <param name="img2">Second image</param>
        /// <returns>OR resulting Bitmap image</returns>
        public Bitmap OR(Image img1, Image img2)
        {
            Bitmap imgResult = new Bitmap(img1.Width, img1.Height);
            int red, green, blue;

            try
            {
                Bitmap img1BMP = new Bitmap(img1);
                Bitmap img2BMP = new Bitmap(this.geometry.BilinearResize(img2, img1.Width, img1.Height));

                for (int i = 0; i < img1.Width; i++)
                {
                    for (int j = 0; j < img1.Height; j++)
                    {
                        red = img1BMP.GetPixel(i, j).R | img2BMP.GetPixel(i, j).R;
                        green = img1BMP.GetPixel(i, j).G | img2BMP.GetPixel(i, j).G;
                        blue = img1BMP.GetPixel(i, j).B | img2BMP.GetPixel(i, j).B;
                        imgResult.SetPixel(i, j, Color.FromArgb(red, green, blue));
                    }
                }

                return imgResult;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Return the negative of the given image
        /// </summary>
        /// <param name="image">Currently displayed image</param>
        /// <returns>Bitmap image. Original image negative</returns>
        public Bitmap ConvertToImageNegative(Image image)
        {
            try
            {
                Bitmap originalImage = new Bitmap(image);
                Bitmap returnImage = new Bitmap(originalImage.Width, originalImage.Height);
                for (int i = 0; i < image.Height; i++)
                {
                    for (int j = 0; j < image.Width; j++)
                    {
                        returnImage.SetPixel(j, i, Color.FromArgb((255 - (int)originalImage.GetPixel(j, i).R), (255 - (int)originalImage.GetPixel(j, i).G), (255 - (int)originalImage.GetPixel(j, i).B)));
                    }
                }

                return returnImage;
            }
            catch (Exception e)
            {
                Logger.LogException(e);
                throw;
            }
        }

        /// <summary>
        /// Convert image to gray scale
        /// </summary>
        /// <param name="image">Currently displayed image</param>
        /// <returns>Bitmap image</returns>
        public Bitmap ConvertToGreyScale(Image image)
        {
            try
            {
                Bitmap originalImage = new Bitmap(image);
                Bitmap returnImage = new Bitmap(originalImage.Width, originalImage.Height);
                int componentsSum = 0;
                for (int i = 0; i < image.Height; i++)
                {
                    for (int j = 0; j < image.Width; j++)
                    {
                        componentsSum = ((int)originalImage.GetPixel(j, i).B + (int)originalImage.GetPixel(j, i).R + (int)originalImage.GetPixel(j, i).G) / 3;
                        returnImage.SetPixel(j, i, Color.FromArgb(componentsSum, componentsSum, componentsSum));
                    }
                }

                return returnImage;
            }
            catch (Exception e)
            {
                Logger.LogException(e);
                throw;
            }
        }
    }
}
